﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace nuc2hex
{
    public class SumMatrix
    {
        public int[,] theMatrix { get; set; }
        public string ErrorString { get; set; }

        public int[] SerializedSumMatrix { get; set; }
        int[] _sortedSumMatrix;
        public int[] SortedSumMatrix
        {
            get
            {
                if (_sortedSumMatrix == null)
                {
                    _sortedSumMatrix = SerializedSumMatrix.OrderBy(v => v).ToArray();
                }
                return _sortedSumMatrix;
            }

        }


        int _greyLevel = 8; // 2 - 8
        public int greyLevel
        {
            get
            {
                return _greyLevel;
            }
            set
            {
                _greyLevel = value;
                if (_greyLevel < 1) _greyLevel = 1;
                if (_greyLevel > 8) _greyLevel = 8;
            }
        }

        int _greys = 0;
        public int greys
        {
            get
            {
                if (_greys == 0)
                {
                    _greys = (int)Math.Pow(2, greyLevel);
                }
                return _greys;
            }
        }

        int[] _medianValues = null;
        public int[] MedianValues
        {
            get
            {
                if (_medianValues == null)
                {
                    _medianValues = new int[greys];
                    int step = SortedSumMatrix.Length / greys;
                    for (int i = 1; i < greys; i++)
                    {
                        _medianValues[i-1] = SortedSumMatrix[i * step];
                    }
                    _medianValues[greys - 1] = SortedSumMatrix[SortedSumMatrix.Length-1];
                }
                return _medianValues;
            }
        }

        int[,] _normalizedSumMatrix = null;
        public int[,] NormalizedSumMatrix
        {
            get
            {
                if (_normalizedSumMatrix == null)
                {
                    _normalizedSumMatrix = new int[256, 256];
                    for (int x = 0; x < 256; x++)
                    {
                        for (int y = 0; y < 256; y++)
                        {
                            int aVal = (from m in MedianValues
                                        where m >= theMatrix[x, y]
                                        select m
                                            ).FirstOrDefault();

                            int a = Array.IndexOf(MedianValues, aVal);
                            if (a >= greys) a = greys - 1;
                            //a = 255 - a;
                            _normalizedSumMatrix[x, y] = a;
                        }
                    }

                }
                return _normalizedSumMatrix;
            }
        }

        public SumMatrix(string fileName, int level)
        {
            ErrorString = "";
            //SortedSet<int> _sortedSumMatrix = new SortedSet<int>();
            try
            {
                greyLevel = level;
                theMatrix = new int[256, 256];
                SerializedSumMatrix = new int[256 * 256];
                int[] SerializedSumMatrix2 = new int[256 * 256];
                int[] SerializedSumMatrix3 = new int[256 * 256];

                using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                using (TextReader reader = new StreamReader(fs))
                {
                    for (int y = 0; y < 256; y++)
                    {
                        string inputStr = reader.ReadLine();
                        string[] arr = inputStr.Split('\t');
                        for (int x = 0; x < 256; x++)
                        {
                            int val = int.Parse(arr[x]);
                            theMatrix[x, y] = val;
                            SerializedSumMatrix[SerializedIndex(x, y)] = val;
                            //bool added = _sortedSumMatrix.Add(val);
                        }
                    }
                    // tests on serialization
                    //int si = 0;
                    //foreach (int val in theMatrix)
                    //{
                    //    SerializedSumMatrix2[si++] = val;
                    //}
                    //Buffer.BlockCopy(theMatrix, 0, SerializedSumMatrix3, 0, theMatrix.Length);

                    //SortedSumMatrix = _sortedSumMatrix.ToArray<int>();
                }

            }
            catch (Exception ex)
            {
                ErrorString = ex.Message;
            }
        }

        private static int SerializedIndex(int x, int y)
        {
            return x + y * 256;
        }

        private int[] SumMatrixSerialize()
        {
            int[] serializedSumMatrix = new int[256 * 256];
            for (int i = 0; i < 256; i++)
                for (int j = 0; j < 256; j++)
                {
                    serializedSumMatrix[i * 256 + j] = theMatrix[i, j];
                }

            return serializedSumMatrix;
        }
    }
}
